﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

/*
 стратегия в следующем:
 * 
 * на каждой новой сделке - проверяем:
 * 1. контрнаправление (да\нет)
 * 2. достигла ли цена середины предыдущей свечи (пересекла ла она её)
 * 3. если пересекла - ставим заявку в сторону текущего микротренда
 * 4. если откатила - проверяем на стоп лосс.
 * 5. если идет дальше по тренду - ждем тэйк.
 */

namespace Atentis_Connector
{
	/// <summary>
	///  Cтратегия Сергея по контртренду
	/// </summary>
	class SergContrTrendStrategy : IStrategy
	{

        private enum ETrendDirection 
        {
            /// <summary>
            /// тренд вверх
            /// </summary>
            tdUpper,
            /// <summary>
            /// тренд вниз
            /// </summary>
            tdDowner,
            /// <summary>
            /// не определенное значение (цена открытия и цена закрытия совпадают)
            /// </summary>
            tdUnknown,
        }

		private Candle m_LastCandle = null;
        private ETrendDirection CandleDirection(Candle candle)
        { return (candle.Close > candle.Open) ? ETrendDirection.tdUpper : ETrendDirection.tdDowner; }
        /// <summary>
        /// Находится ли текщая свеча в контртренде
        /// </summary>
        /// <param name="candle"></param>
        /// <returns></returns>
        private bool IsConterTrendNow(Candle candle)
		{ return (CandleDirection(candle) != CandleDirection(m_LastCandle)); }
        /// <summary>
        /// Есть ли контр-пересечение на текущей свече.
        /// </summary>
        /// <param name="candle"></param>
        /// <returns></returns>
        private bool IsConterCross(Candle candle)
        {
            bool res = false;
            if (candle != null && IsConterTrendNow(candle))
            {
                if (CandleDirection(candle) == ETrendDirection.tdDowner)
                    return candle.Close < (m_LastCandle.High + m_LastCandle.Low) / 2;
                else
                if (CandleDirection(candle) == ETrendDirection.tdUpper)
                    return candle.Close > (m_LastCandle.High + m_LastCandle.Low) / 2;
            }
            return res;
        }

        private double m_LastSellPrice;
		private double m_LastBuyPrice;

		private string m_SecCode;
		/// <summary>
		/// Кодовое название бумаги
		/// </summary>
		public string SecCode { get { return m_SecCode; } set { m_SecCode = value; } }

		private StrategySettings m_StrategySettings;
		public StrategySettings StrategySettings { get { return m_StrategySettings; } set { m_StrategySettings = value; } }

		/// <summary>
		/// Название стратегии
		/// </summary>
		public static string StrategyName { get { return "Стратегия Ы!"; } }

		private List<Candle> m_Candles;
		private StockViewer m_StockViewer;

		/// <summary>
		/// Событие - форма с графиком закрыта
		/// </summary>
		public event EventHandler CloseStrategy;
		void OnCloseStrategy(EventArgs e)
		{
			EventHandler closeStrategy = CloseStrategy;
			if (closeStrategy != null)
				closeStrategy(this, e);
		}
		private Dictionary<int, decimal> m_SmaValues;
        private Dictionary<int, decimal> m_VolValues;

		private Dictionary<int, decimal> m_AOValues;

		public double Price { get { return m_Candles.Last().Close; } }

		const int SMAPERIOD = 7;

		private bool MayInSellPosition;
		private bool MayInBuyPosition;

		private bool IsUpSaucer;
		private bool IsDownSaucer;

		private bool IsUpCross;
		private bool IsDownCross;

        public SergContrTrendStrategy()
		{

			m_Candles = new List<Candle>();
			m_SmaValues = new Dictionary<int, decimal>();
            m_VolValues = new Dictionary<int, decimal>();

			m_StockViewer = new StockViewer();
			m_StockViewer.CloseForm += m_StockViewer_CloseForm;
			//Для отображения SMA
			m_StockViewer.Indicators.Add(new Dictionary<int, decimal>());
			//Для объемов Vol
			m_StockViewer.Indicators.Add(new Dictionary<int, decimal>());
			CropLastValues(10);

			StrategySettings = new StrategySettings(1000,10,10, 15, 20, 50, false, false);
			m_LastSellPrice = 0;
			m_LastBuyPrice = 0;

			MayInSellPosition = false;
			MayInBuyPosition = false;
		}

		private void CropLastValues(int n)
		{
			// Отрезаем последние n значений, чтобы не грузить комп
			m_StockViewer.DrawLast = n;
		}

		void m_StockViewer_CloseForm(object sender, EventArgs e)
		{
			OnCloseStrategy(new EventArgs());
		}
		
		public event EventHandler<AtentisConnectorEventArgs> NeedSell;
		void OnNeedSell(AtentisConnectorEventArgs e)
		{
			EventHandler<AtentisConnectorEventArgs> needSell = NeedSell;
			if (needSell != null)
				needSell(this, e);
		}
		public event EventHandler<AtentisConnectorEventArgs> NeedBuy;
		void OnNeedBuy(AtentisConnectorEventArgs e)
		{
			EventHandler<AtentisConnectorEventArgs> needBuy = NeedBuy;
			if (needBuy != null)
				needBuy(this, e);
		}

		public event EventHandler<AtentisConnectorEventArgs> CloseSell;
		void OnCloseSell(AtentisConnectorEventArgs e)
		{
			EventHandler<AtentisConnectorEventArgs> closeSell = CloseSell;
			if (closeSell != null)
				closeSell(this, e);
		}
		public event EventHandler<AtentisConnectorEventArgs> CloseBuy;
		void OnCloseBuy(AtentisConnectorEventArgs e)
		{
			EventHandler<AtentisConnectorEventArgs> closeBuy = CloseBuy;
			if (closeBuy != null)
				closeBuy(this, e);
		}
		/// <summary>
		/// Установить историю
		/// </summary>
		/// <param name="candles">Список свечей</param>
		public void SetHistory(List<Candle> candles)
		{
			m_Candles.Clear();
			for (int i = 0; i < candles.Count - 1; i++)
			{
				NewCandle(candles[i]);
			}
		}

		/// <summary>
		/// Добавить свечу
		/// </summary>
		/// <param name="candle">Свеча</param>
		public void NewCandle(Candle candle)
		{
			if (m_Candles.Count>0)
				 PorcessCandle(m_Candles.Last());
			m_Candles.Add(candle);
			//ProcessTrade(candle);
			m_StockViewer.DrawCandlesAndIndicators(m_Candles);
		}

		/// <summary>
		/// Дабавить сделку
		/// </summary>
		/// <param name="trade">Сделка</param>
		public void NewTrade(WrapperTrades trade)
		{
			if (m_Candles.Count() > 0)
			{
				m_Candles.Last().Close = trade.Price;
				//PorcessCandle(m_Candles.Last());
				ProcessTrade(m_Candles.Last());
				m_StockViewer.DrawCandlesAndIndicators(m_Candles);
			}
		}

		#region Формирование сигналов
		/// <summary>
		/// Формирование сигналов по последней сформированной свече
		/// </summary>
		/// <param name="candle">Свеча</param>
		private void PorcessCandle(Candle candle)
		{
            //SMA
            m_StockViewer.Indicators[0] = m_SmaValues;
            //Vols
            m_VolValues.Add(m_VolValues.Count, (decimal)candle.Volume);
            m_StockViewer.Indicators[1] = m_VolValues;
            //m_StockViewer.Indicators[0] = m_SmaValues;
            if (m_LastCandle != null)
                candelsAfterImportantCandle++;
            else
                candelsAfterImportantCandle = 0;
        }

		#endregion Формирование сигналов

        int candelsAfterImportantCandle = 0;
		private double m_SellPrice = -1;
        private int m_SellVol = -1;
		private double m_BuyPrice = -1;
        private int m_BuyVol = -1;

		#region Проверка условий стратегии
		private void ProcessTrade(Candle candle)
		{
			var candleHeight = candle.High - candle.Low;

			if (candleHeight > StrategySettings.MinCandleSize && 
                !MayInSellPosition && 
                !MayInBuyPosition && 
                candle.Volume >= StrategySettings.Vol)
				m_LastCandle = candle;
			if (m_LastCandle == null) return;
            if (candelsAfterImportantCandle > 3)
            {
                candelsAfterImportantCandle = 0;
                m_LastCandle = null;
            }
            if (IsConterCross(candle))
            {
                var lastCenter = (m_LastCandle.High - m_LastCandle.Low)/2;
				//если опорная свеча лонговая
				if (CandleDirection(m_LastCandle) == ETrendDirection.tdUpper)
				{
					if (!MayInSellPosition && !MayInBuyPosition)
					{
						var sellPrice = m_LastCandle.High - candleHeight * (double)StrategySettings.Threshold / 100;
						MayInSellPosition = true;
						var tradeInfo = new OrderInfo();
						tradeInfo.Price = sellPrice;
						tradeInfo.BS = "S";
						tradeInfo.IsLimit = true;
						tradeInfo.Vol = -1;
						OnNeedSell(new AtentisConnectorEventArgs(tradeInfo));
					}
				}

				//если опорная свеча шорт
				if (CandleDirection(m_LastCandle) == ETrendDirection.tdDowner)
				{
					if (!MayInSellPosition && !MayInBuyPosition)
					{
						var buyPrice = m_LastCandle.Low + candleHeight * (double)StrategySettings.Threshold / 100;
						MayInSellPosition = true;
						var tradeInfo = new OrderInfo();
						tradeInfo.Price = buyPrice;
						tradeInfo.BS = "B";
						tradeInfo.IsLimit = true;
						tradeInfo.Vol = -1;
						OnNeedBuy(new AtentisConnectorEventArgs(tradeInfo));
					}
				}
            }
			if (MayInSellPosition && m_SellPrice > 0)
			{
				//проверка на стоплосс
				//и
				//проверка на тэйкпрофит
				if ((!IsConterCross(candle) && candle.Close - m_SellPrice > (double)StrategySettings.StopLoss) || 
					(IsConterCross(candle) && m_SellPrice - candle.Close > (double)StrategySettings.TakeProfit))
				{
					MayInSellPosition = false;
					OnCloseSell(new AtentisConnectorEventArgs(new OrderInfo()));
					m_SellPrice = -1;
				}
			}
			if (MayInBuyPosition && m_BuyPrice > 0)
			{
				//проверка на стоплосс
				//и
				//проверка на тэйкпрофит
				if ((IsConterCross(candle) && candle.Close - m_BuyPrice > (double)StrategySettings.TakeProfit) ||
					(!IsConterCross(candle) && m_BuyPrice - candle.Close > (double)StrategySettings.StopLoss))
				{
					MayInBuyPosition = false;
					OnCloseBuy(new AtentisConnectorEventArgs(new OrderInfo()));
					m_BuyPrice = -1;
				}
			}
        }
		#endregion Проверка условий стратегии

		/// <summary>
		/// Закрыть окно данной стратегии.
		/// </summary>
		public void RemoveThatStrategy()
		{
			m_StockViewer.CloseThatForm();
		}

		string IStrategy.StrategyName
		{
			get { return StrategyName; }
		}

        public void OnSellOrderComplete(int vol, double price)
        {
            //исполнено начало стратегии, ждем исполнения тэйка или стопа
            if (MayInSellPosition)
            {
                m_SellPrice = price;
            }
        }
        public void OnBuyOrderComplete(int vol, double price)
        {
            if (MayInBuyPosition)
            {
                m_BuyPrice = price;
            }
        }

	}
}

